namespace Warehouse

open System
open System.Collections.ObjectModel
open System.Windows
open Microsoft.VisualBasic
open System.Data
open FSharp.Windows

type InventoryController(?repository) = 
    inherit Controller<InventoryEvents, InventoryModel>()

    let repository = defaultArg repository (new DataModel.Repository())

    override this.InitModel model = 
        model.ProductSearch <- Model.Create()

    override this.Dispatcher = function
        | Edit -> Sync this.Edit
        | AdjustingQuantityPerUPC x -> Sync(this.AdjustQuantityPerUPC x)
        | SeparateUpcToProduct -> Sync this.SeparateUpcToProduct
        | MergeUpcIntoAnotherProduct -> Sync this.MergeUpcIntoAnotherProduct

    member this.Edit model = 
        let product = model.ProductSearch.SelectedProduct
        let mvc = Mvc(product, ProductView(), ProductController(repository))
        let saveChanges = mvc.StartDialog()
        if not saveChanges
        then
            product.DiscardChanges()
            for upc in product.UPCs do
                upc.Quantity <- repository.AvailableQuantityByUPC upc.Entity
            product.Compute()
        elif product.Entity.EntityState = EntityState.Detached 
        then
            let deleted = model.ProductSearch.Products.Remove product 
            assert deleted 

    member this.AdjustQuantityPerUPC (newQuantity, cancel) model = 
        let adjustBy = newQuantity - model.SelectedUpc.Quantity 
        if adjustBy <> 0 
        then
            let adjustment = 
                DataModel.Adjustment(Date = DateTime.Now, UpcId = model.SelectedUpc.Entity.Id, Quantity = adjustBy)
            let prompt = 
                sprintf "Would you like quantity of %s to be adjusted by %i? " model.SelectedUpc.Code adjustBy
            match Interaction.InputBox(prompt, Title = "Quantity changed!!!", DefaultResponse = "<Enter note>") with
            | "" -> cancel()
            | note -> 
                adjustment.Note <- note
                repository.Adjustments.AddObject adjustment
                let affectedRecords = repository.SaveChanges()
                assert (affectedRecords > 0)

    member this.SeparateUpcToProduct model = 
        let newProduct : ProductModel = Model.Create()
        let selectedProduct = model.ProductSearch.SelectedProduct
        newProduct.UPCs <- ObservableCollection.singleton model.SelectedUpc
        let mvc = Mvc(newProduct, ProductView(), ProductController repository)
        let saveChanges = mvc.StartDialog()
        if saveChanges
        then
            let quantity = model.SelectedUpc.Quantity
            selectedProduct.UPCs.Remove model.SelectedUpc |> ignore
            selectedProduct.SaveEntity repository
            model.ProductSearch.Products.Add newProduct

    member this.MergeUpcIntoAnotherProduct model = 
        let productToMerge = model.ProductSearch.SelectedProduct
        let searchProductMergeInto : ProductSearchModel = Model.Create() 
        searchProductMergeInto.AppFilter <- fun p -> p.Entity.Id <> productToMerge.Entity.Id
        let mvc = ProductSeach.createMvc searchProductMergeInto repository
        if mvc.StartDialog() then
            let productMergeInto = searchProductMergeInto.SelectedProduct
            assert (productMergeInto.Entity.Id <> productToMerge.Entity.Id)
            let mvc = Mvc(productMergeInto, ProductView(), ProductController repository)
            productMergeInto.UPCs.Add <| model.SelectedUpc
            let saveChanges = mvc.StartDialog()
            if saveChanges
            then
                let quantity = model.SelectedUpc.Quantity

                productToMerge.UPCs.Remove model.SelectedUpc |> ignore
                productToMerge.DeleteEntity repository
                repository.SaveChanges() |> ignore

                model.ProductSearch.Products.Remove productToMerge |> ignore
                model.ProductSearch.SelectedProduct <- productMergeInto


